Try Haskell!

Haskell is a modern purely functional programming language, backed by a large open-source community, a large package database, suitable for tackling difficult problems on a commercial scale.

Welcome to IHaskell, Haskell running on a Jupyter temporary notebook! This notebook provides you a way to quickly experiment with Haskell and the Jupyter notebook interface. (This server will be deleted after ten minutes of inactivity.)

Run some Haskell code!

The Jupyter interface is divided into cells. Some cells, like this one, have markdown and other media content. Other cells, like the one below, contain code.

  1. Select the cell below this one by click in on it.
  2. Run the cell by pressing SHIFT-ENTER (or the play button in the toolbar at the top).

In [2]:
-- List of all natural numbers.
naturals :: [Integer]
naturals = [1..]

-- List of all even naturals.
evens :: [Integer]
evens = filter isEven naturals
  where isEven x = x `mod` 2 == 0
  
-- Print the first ten even integers.
-- If we wrote `print evens`, our code would run forever.
print (take 10 evens)


[2,4,6,8,10,12,14,16,18,20]

More Info

You can find more information on using the Jupyter notebook interface here. If you'd like to install IHaskell locally, follow these instructions, and file issues if you run into trouble.

IHaskell can be customized for rich displays and interactive media for any library; some demos are available in the full IHaskell demo notebook.

Another Code Snippet

If you want a few more code snippets to play with, here's the code from haskell.org for (very slowly) finding primes. (This isn't a prime seive, and is very slow, so don't use it anywhere important! It's suitable more or less only for getting a feel for Haskell syntax.)


In [3]:
primes :: [Int]
primes = filterPrime [2..] 
  where filterPrime (p:xs) = 
          p : filterPrime [x | x <- xs, x `mod` p /= 0]
          
putStrLn $ concat ["The 100th prime is ", show (primes !! 99), "!"]


The 100th prime is 541!

Parsing

Haskell's monadic parser combinator libraries make writing parsers incredibly easy, making prototyping custom textual formats and small parsers very quick. For example, where in another language you may turn to a regular expression as a quick-and-dirty solution, parsec makes writing parsers so easy that it is your go-to tool instead.

Below is a small code snippet for parsing US phone numbers.


In [9]:
import Text.Parsec
import Text.Parsec.String

-- Parse a single digit
digit :: Parser Char
digit = oneOf ['0'..'9']

-- Parse a multi-digit number.
number :: Parser Integer
number = do
  digits <- many1 digit -- At least one digit
  return (read digits)  -- Convert [Char] to Integer
  
-- Parse a country code, starting with a +.
countryCode :: Parser Integer
countryCode = do
  char '+'
  number
  
-- Parse an area code, optionally with parentheses.
areaCode :: Parser Integer
areaCode = choice [withParens, withoutParens]
  where
    withParens = between (char '(') (char ')') withoutParens
    withoutParens = number
  
-- Simple data type representing a phone number.
-- Real phone numbers are much more complex!
data PhoneNumber = PhoneNumber {
    phoneCountryCode :: Maybe Integer,
    phoneNumbers :: [Integer]
  } deriving (Eq, Show)
  
phoneNumber :: Parser PhoneNumber
phoneNumber = do
  -- Try to parse a country code. If it doesn't work, it's Nothing.
  c <- optionMaybe countryCode
  optional separator
  a1 <- areaCode
  separator -- Separator required after area code
  a2 <- number
  separator -- Separator required before last group of digits
  a3 <- number
  return (PhoneNumber c [a1, a2, a3])
  
  where
    separator = oneOf " -"

We can use this to parse phone numbers from strings:


In [11]:
parsePhoneNumber :: String -> Maybe PhoneNumber
parsePhoneNumber str = case parse phoneNumber "<interactive>" str of
  Left _ -> Nothing
  Right x -> Just x
  
print (parsePhoneNumber "+1 (327)-525 3029")


Just (PhoneNumber {phoneCountryCode = Just 1, phoneNumbers = [327,525,3029]})

This parser is of course much longer than an equivalent regular expression, but much easier to get sane error messages out of, and much more maintainable as a result:


In [14]:
parse phoneNumber "example" "+1 (327)x525x3029"


Left "example" (line 1, column 9):
unexpected "x"